package thu.infinity.facebook;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TIOStreamTransport;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import thu.infinity.commons.AggregatorHandler;
import thu.infinity.commons.Task;
import thu.infinity.facebook.FacebookError;
import thu.infinity.facebook.FacebookUtil;
import thu.infinity.commons.Para;
import thu.infinity.thrift.Constants;
import thu.infinity.thrift.FriendAlbum;
import thu.infinity.thrift.FriendEntry;
import thu.infinity.thrift.PhotoEntry;

public class QueryFriendsTask extends Task {
	FacebookUser fbUser;
	
	public class MyAlbum implements Comparable<MyAlbum> {
		String id;
		String updated_time;
		String name;
		int type = Constants.PhotoEntryTypePhoto;; 
		int count;
		
		@Override
		public int compareTo(MyAlbum another) {
			return another.updated_time.compareTo(this.updated_time);
		}
	}
	
	//A helper class to be used as parameters passed to function calls, when time is updated,
	//it is also reflected in the caller side
	public class MyTime {
		public String time;
		
		public MyTime(String time) {
			this.time = time;
		}
		
		public MyTime() {
			this.time = Para.DefaultStartTime;
		}		
	}
	
	public QueryFriendsTask(long expireTime, long period) {
		super(expireTime, period);
		// TODO Auto-generated constructor stub
	}
	
	public QueryFriendsTask(FacebookUser fbUser, AggregatorHandler handler) {
		this.fbUser = fbUser;
		this.handler = handler;
		this.isPeriodical = false;
	}
	
	public void getFriendsInfo(Vector<String> infoUrl) {
		
	}
	
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		Vector<String> allAlbumUrl = new Vector<String>();
		Vector<String> allInfoUrl = new Vector<String>();
		Vector<String> friendsNo = new Vector<String>();
		Vector<String> infoUrl = new Vector<String>();
		
		for (int i = 0; i < fbUser.friends.length; i++) {
			if (fbUser.friendsNewUser[i]) {
				allInfoUrl.add(fbUser.friends[i]);
				allInfoUrl.add(fbUser.friends[i] + "/albums");
			}
		}
		
		// For new friend, get friend info
		if (allInfoUrl.size() > 0) {
			System.out.println("  getFriendInfo");
			try {
				JSONArray allInfo = fbUser.fbconn.batchAllGet(allInfoUrl);
				Vector<String> allProfileUrl = new Vector<String>();
				Vector<FriendAlbum> allFrndAlbum = new Vector<FriendAlbum>();
				
				for (int i = 0; i < allInfoUrl.size()/2; i++) {
					String infoRes = allInfo.getJSONObject(i*2).getString("body");
					JSONObject infoJson = FacebookUtil.parseJson(infoRes);
					
					FriendAlbum frndAlbum = new FriendAlbum();
					frndAlbum.friend = new FriendEntry();
					frndAlbum.friend.id = infoJson.getString("id");
					frndAlbum.friend.name = infoJson.getString("name");
					
					System.out.println("getFriendInfo " + frndAlbum.friend.id + " " + frndAlbum.friend.name);
					
					frndAlbum.friend.profilePicId = new PhotoEntry();
					frndAlbum.friend.profilePicId.id = null;
					frndAlbum.updatedTime = Para.DefaultStartTime;
					frndAlbum.photos = new ArrayList<PhotoEntry> ();
					
					infoRes = allInfo.getJSONObject(i*2+1).getString("body");
					JSONObject albumJson = FacebookUtil.parseJson(infoRes);
					JSONArray albumArray = albumJson.getJSONArray("data");
					
					allFrndAlbum.add(frndAlbum);
					for (int j = 0; j < albumArray.length(); j++) {
						JSONObject album = albumArray.getJSONObject(j);
						if (album.getString("type").compareTo("profile") == 0) {
							allProfileUrl.add(album.getString("id") + "/photos");
							friendsNo.add(frndAlbum.friend.id);
						}
					}
				}
				
				JSONArray allProfile = fbUser.fbconn.batchAllGet(allProfileUrl);
				for (int i = 0, no = 0; i < allFrndAlbum.size(); i++) {
					System.out.println("Friend "+i+ " :"+allFrndAlbum.get(i).friend.id+" profile photo...");
					if (allFrndAlbum.get(i).friend.id.compareTo(friendsNo.get(no)) == 0) {
						String profileRes = allProfile.getJSONObject(no).getString("body");
						JSONObject photoJson = FacebookUtil.parseJson(profileRes);
						JSONArray photoArray = photoJson.getJSONArray("data");
						no++;
						if (photoArray.length() > 0) {
							JSONObject pic = photoArray.getJSONObject(0);
							CacheProfileTask cacheProfile = new CacheProfileTask(fbUser.uid, allFrndAlbum.get(i), pic, handler);
							handler.getScheduler().AddTask(cacheProfile);
							continue;
						}
					}
					
					String fn = Util.friendAlbumName(fbUser.uid, allFrndAlbum.get(i).friend.id);
					File f = Util.newFile (fn);
					FacebookUtil.writeFriendAlbumToFile(allFrndAlbum.get(i), f);
				}
				System.out.println("get Friends info end.");
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (FacebookError e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (TException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		for (int i = 0; i < fbUser.friends.length; i++) {
			allAlbumUrl.add(fbUser.friends[i] + "/albums");
		}
		
		try {
			JSONArray allAlbum = fbUser.fbconn.batchAllGet(allAlbumUrl);
			//The list of albums that have been updated
			Vector<MyAlbum> albumList = new Vector<MyAlbum> ();
			//System.out.println(allAlbum.toString());
			for (int i = 0; i < 2; i++) {   ////fbUser.friends.length
				String albumRes = allAlbum.getJSONObject(i).getString("body");
				//System.out.println("      " + i + ":");
				//System.out.println(albumRes.toString());
				JSONObject albumJson = FacebookUtil.parseJson(albumRes);
				JSONArray albumArray = albumJson.getJSONArray("data");

				//Check the tagged photo of the user, which is under /me/photos
				MyAlbum mAlbum1 = new MyAlbum();
				mAlbum1.type = Constants.PhotoEntryTypePhoto;
				
				MyAlbum mAlbum2 = new MyAlbum();
				mAlbum2.type = Constants.PhotoEntryTypeVideo;
				
				String fid = fbUser.friends[i];
				if (i == 0){
					mAlbum1.id = fbUser.uid;
					mAlbum2.id = fbUser.uid;					
				} else {
					mAlbum1.id = fid;
					mAlbum2.id = fid;					
				}
				
				albumList.add(mAlbum1);
				albumList.add(mAlbum2);

				//System.out.println("Before largetTime");
				MyTime largetTime = new MyTime();
				synchronized (fbUser.updatedTime[i]) {
					largetTime.time = fbUser.updatedTime[i];
				}
				//System.out.println("Begin parse.");
				fbUser.friendsAlbumNum[i] = albumArray.length();
				for (int j = 0; j < 1 && j < albumArray.length(); j++) {
					System.out.println("   albumArray: " + j);
					MyAlbum mAlbum = new MyAlbum();
					mAlbum.type = Constants.PhotoEntryTypePhoto;

					JSONObject album;
					try {
						album = albumArray.getJSONObject(j);

						mAlbum.id = album.getString("id");
						if (album.has("updated_time")) {
							mAlbum.updated_time = album.getString("updated_time");
						} else {
							mAlbum.updated_time = album.getString("created_time");
						}
						mAlbum.name = album.getString("name");
						//System.out.println("      Debug mAlbum name");
						//Check whether the latest update of the album is cached
						
						//if (mAlbum.updated_time.compareTo(fbUser.updatedTime[i]) > 0) {
							albumList.add(mAlbum);
						//}
						//System.out.println("      Debug add mAlbum");
						//if (mAlbum.updated_time.compareTo(largetTime.time) > 0) {
						//	System.out.println("***Largest time updated from " + largetTime + " to " + mAlbum.updated_time);
						//	largetTime.time = mAlbum.updated_time;
						//}
					} catch (JSONException e) {
						e.printStackTrace();
					}
				}
				//System.out.println("End Parse");
				//System.out.println("AlbumListSize " + albumList.size());
			}
			System.out.println("Albumlist size: " + albumList.size());
	
			if (albumList.size() > 0) {
				QueryAlbumsTask qryAlbums = new QueryAlbumsTask(fbUser, albumList, handler);
				handler.getScheduler().AddTask(qryAlbums);
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FacebookError e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public boolean checkCondition() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	protected Task genNextTask() {
		// TODO Auto-generated method stub
		return null;
	}
}
